#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/types.h>			/* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>

#if 0
int epoll_create(int size);
int socket(int domain, int type, int protocol);
int inet_pton(int af, const char *src, void *dst);
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

/* Internet address. */
struct in_addr {
	uint32_t	   s_addr;	   /* address in network byte order */
};

struct sockaddr_in {
	sa_family_t    sin_family; /* address family: AF_INET */
	in_port_t	   sin_port;   /* port in network byte order */
	struct in_addr sin_addr;   /* internet address */
};


typedef union epoll_data {
	void		*ptr;
	int 		 fd;
	uint32_t	 u32;
	uint64_t	 u64;
} epoll_data_t;

struct epoll_event {
	uint32_t	 events;	  /* Epoll events */
	epoll_data_t data;		  /* User data variable */
};
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
#endif

#define SERVER_PORT 8090
#define BUFFER_SIZE 1024

typedef int (*NCALLBACK)(int fd, void *arg);

typedef struct event_item{
	int fd;
	void *arg;
	int event;
	NCALLBACK readcb;
	NCALLBACK writecb;
	NCALLBACK acceptcb;
	unsigned char recvbuf[BUFFER_SIZE];
	unsigned char sendbuf[BUFFER_SIZE];
}event_item_t;

typedef struct block{
	event_item_t *item_array;
	struct block *next;
}blk_t;

typedef struct nreactor{
	int epfd;
	blk_t *head;
}nreactor_t;

int accept_callback(int fd, void *arg);
int read_callback(int fd, void *arg);
int write_callback(int fd, void *arg);

int init_server(int port){
	struct sockaddr_in serv;
	socklen_t addrlen = sizeof(struct sockaddr_in);
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0){
		perror("socket() error:\n");
		return -1;
	}
	
	memset(&serv, 0, sizeof(struct sockaddr_in));
	serv.sin_family = AF_INET;
	serv.sin_port = htons(SERVER_PORT);
	serv.sin_addr.s_addr = htonl(INADDR_ANY);

	int optname = 1;
	int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optname, sizeof(optname));
	if(ret < 0){
		perror("setsockopt() error:\n");
		close(fd);
		return -1;
	}

	ret = bind(fd, (const struct sockaddr *)&serv, addrlen);
	if(ret < 0){
		perror("bind() error:\n");
		close(fd);
		return -1;
	}
	
	ret = listen(fd, 128);
	if(ret < 0){
		perror("listen() error:\n");
		close(fd);
		return -1;
	}

	return fd;	
}

event_item_t *findItemPosition(blk_t *head, int fd){
	int block_id = fd / 1024;
	int index = fd % 1024;
	int i = 0;

	blk_t *block = head;
	blk_t *newBlock = NULL;
	while(block_id-- > 0 ){
		if(block->next != NULL){
			block = block->next;
		}else{
			newBlock = (blk_t *)malloc(sizeof(blk_t));
			if(newBlock == NULL){
				return NULL;
			}
			memset(newBlock, 0, sizeof(blk_t));
			
			newBlock->item_array = malloc(sizeof(event_item_t) * 1024);
			if(newBlock->item_array == NULL){
				return NULL;
			}
			memset(newBlock->item_array, 0, sizeof(event_item_t) * 1024);
			block->next = newBlock;
			block = newBlock;
		}
	}
	return &(block->item_array[index]);
}

int accept_callback(int fd, void *arg){
	nreactor_t *rect = (nreactor_t *)arg;
	struct sockaddr_in cli;
	socklen_t addrlen = 0;
	//char client_addr[INET_ADDRSTRLEN] = {0};
	memset(&cli, 0, sizeof(struct sockaddr_in));

	printf("accept_callback: 111\n");
	int connfd = accept(fd, (struct sockaddr*)&cli, &addrlen);
	if(connfd < 0){
		perror("accept() error:");
		return -1;
	}

	printf("aaa\n");
	printf("new client connected-> [%s:%d], connfd = [%d]\n", inet_ntoa(cli.sin_addr), ntohs(cli.sin_port), connfd);
	printf("bbb"); 
	
	//原来处理方式:
	//event_item_t *item = &(rect->head->item_array[connfd]);
	//动态扩展：
	event_item_t *item  = findItemPosition(rect->head, connfd);
	item->event = EPOLLIN;
	item->fd = connfd;
	item->arg = rect;
	item->readcb = read_callback;
	
	//添加connfd 到epoll树上
	struct epoll_event event = {0};
	event.events = EPOLLIN;
	event.data.fd = connfd;
	event.data.ptr = item;
 	epoll_ctl(rect->epfd, EPOLL_CTL_ADD, connfd, &event);

	return 0;
} 

int read_callback(int fd, void *arg){
	nreactor_t *rect = (nreactor_t *)arg;
	event_item_t *item = &(rect->head->item_array[fd]);
	memset(item->recvbuf, 0, sizeof(item->recvbuf));
	struct epoll_event event = {0};

	int n = read(fd, item->recvbuf, sizeof(item->recvbuf));
	if(n == 0){
		printf("client [%d] disconnected!\n", fd);
		event.events = EPOLLIN;
		event.data.fd = fd;
		event.data.ptr = item;
	 	epoll_ctl(rect->epfd, EPOLL_CTL_DEL, fd, &event);
		close(fd);
	}else{
		item->recvbuf[strcspn(item->recvbuf, "\n")] = 0;  // 去除换行符
		printf("n = [%d], recv:[%s]\n",n,  item->recvbuf);
		item->event = EPOLLOUT;
		item->writecb = write_callback;
		event.events = EPOLLOUT;
		event.data.fd = fd;
		event.data.ptr = item;
	 	epoll_ctl(rect->epfd, EPOLL_CTL_MOD, fd, &event);	
	}
	return 0;
}

int write_callback(int fd, void *arg){
	nreactor_t *rect = (nreactor_t *)arg;
	event_item_t *item = &(rect->head->item_array[fd]);
	struct epoll_event event = {0};

	printf("write_callback(): item = [%p], item->fd = [%d], item->recvbuf = [%s]\n", item, item->fd, item->recvbuf);
	//数据回发
	int n = write(fd, item->recvbuf, strlen(item->recvbuf));
	if(n == 0){
		printf("client [%d] disconnected!\n", fd);
		item->fd = -1;
		event.events = EPOLLOUT;
		event.data.fd = fd;
		event.data.ptr = item;
	 	epoll_ctl(rect->epfd, EPOLL_CTL_DEL, fd, &event);
		close(fd);
	}else{
		printf("n = [%d], recv:[%s]\n",n,  item->recvbuf);
		item->event = EPOLLIN;
		event.events = EPOLLIN;
		event.data.fd = fd;
		event.data.ptr = item;
	 	epoll_ctl(rect->epfd, EPOLL_CTL_MOD, fd, &event);	
	}
	return 0;
} 

int nreactor_loop(nreactor_t *rect, int listenfd){
	if(rect == NULL) return -1;
	struct epoll_event events[1024] = {0};
	int nready = 0, i = 0;
	int fd = -1;
	event_item_t *item = NULL;

	while(1){
		nready = epoll_wait(rect->epfd, events, 1024, -1);
		if(nready < 0){
			continue;
		}

		printf("nreactor_loop(): nready = [%d]\n", nready);
		for(i = 0; i < nready; i++){
			item = (event_item_t *)events[i].data.ptr;
			fd = item->fd; //问题1：events[i].data.fd; 为啥这个fd是个超级大的数
			if(fd == listenfd){
				item->acceptcb(fd, rect);
			}else{
				if(events[i].events == EPOLLIN){
					item->readcb(fd, rect);
				}
 
				if(events[i].events == EPOLLOUT){
					item->writecb(fd, rect);
				}
			}
		}
	}
	return 0;
}

nreactor_t * nreactor_init(int listenfd){
	nreactor_t *rect = (nreactor_t *)malloc(sizeof(nreactor_t));
	if(rect == NULL){
		printf("nreactor_init() malloc error 1:\n");
		return NULL;
	}
	memset(rect, 0, sizeof(nreactor_t));
	rect->epfd = epoll_create(1);
	if(rect->epfd < 0){
		perror("epoll_create() error:");
		return NULL;
	}
	
	rect->head = (blk_t *)malloc(sizeof(blk_t));
	if(rect->head == NULL){
		printf("nreactor_init() malloc error 2:\n");
		close(rect->epfd);
		return NULL;
	}
	memset(rect->head, 0, sizeof(blk_t));
		
	rect->head->item_array = (event_item_t *)malloc(sizeof(event_item_t) * 1024);
	if(rect->head->item_array == NULL){
		printf("nreactor_init() malloc error 3:\n");
		free(rect->head);
		close(rect->epfd);
		return NULL;
	}
	memset(rect->head->item_array, 0, sizeof(event_item_t) *1024);
	//rect->head = rect->tail;
	//rect->head->next = NULL;
	
	//设置listenfd 的item位置 
	event_item_t *item = &(rect->head->item_array[listenfd]);	
	item->event = EPOLLIN;
	item->fd = listenfd;
	item->arg = rect;
	item->acceptcb = accept_callback;

	printf("item = [%p], item->event = [%d], item->fd = [%d]\n",item, item->event, item->fd);

	//添加listenfd 到epoll树上
	struct epoll_event event = {0};
	event.events = EPOLLIN;
	event.data.fd = listenfd;
	event.data.ptr = (void*)item;
 	int ret = epoll_ctl(rect->epfd, EPOLL_CTL_ADD, listenfd, &event);
	if(ret < 0){
		perror("epoll_ctl() error:");
	}
	return rect;
}

void nreactor_destroy(nreactor_t *rect){
	if(rect == NULL) return;
	close(rect->epfd);
	blk_t *block = rect->head;
	while(block != NULL){
		blk_t *tmp = block->next;
		free(block->item_array);
		block->item_array = NULL;
		free(block);
		block = tmp;
	}
	free(rect);
	rect = NULL;
	return;
}

int main(int argc, char *argv[]){
	int listenfd = init_server(SERVER_PORT); 
	if(listenfd < 0){
		printf("init_server() error:\n");
		exit(-1);
	}

	printf("init_server()->: listenfd = [%d]\n", listenfd);
	nreactor_t *rect = nreactor_init(listenfd);
	if(rect == NULL){
		printf("nreactor_init() error:\n");
		goto destory;
	}

	nreactor_loop(rect, listenfd);
	
destory:
	nreactor_destroy(rect);
	close(listenfd);
	return 0;
}
